{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Neo4j  \n",
    "[neo4j DockerHub](https://hub.docker.com/_/neo4j/)      \n",
    "[py2neo文档](https://py2neo.readthedocs.io/en/latest/database/index.html)  \n",
    "[neorj cypher文档](https://neo4j.com/docs/cypher-manual/4.1/)  \n",
    "docker run -itd --rm --name vincent_neo4j -p 7474:7474 -p 7687:7687 -v $HOME/neo4j/data:/data  neo4j:latest   \n",
    "http://192.168.214.66:7474/browser/   (创建修改密码。 初始用户/密码 neo4j)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "py2neo Version：2020.0.0\n",
      "当前时间：20210111  10:54:25\n"
     ]
    }
   ],
   "source": [
    "from py2neo import Graph, Node, Relationship\n",
    "\n",
    "import py2neo\n",
    "print('py2neo Version：{}'.format(py2neo.__version__))\n",
    "\n",
    "import time\n",
    "print('当前时间：{}'.format(time.strftime('%Y%m%d  %H:%M:%S', time.localtime(time.time()))))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Graph('http://neo4j@192.168.214.66:7474', name='neo4j')\n",
      " name         | versions  | edition   \n",
      "--------------|-----------|-----------\n",
      " Neo4j Kernel | ['4.1.1'] | community \n",
      "\n",
      "\n",
      "Graph node_labels:\n",
      " frozenset()\n",
      "\n",
      "Graph relationship_types:\n",
      " frozenset()\n"
     ]
    }
   ],
   "source": [
    "# 连接neo4j数据库，输入地址、用户名、密码\n",
    "graph = Graph('http://192.168.214.66:7474', username='neo4j', password='vincent')\n",
    "print(graph)\n",
    "print(graph.call.dbms.components())\n",
    "\n",
    "# 删除当前图所有节点\n",
    "graph.delete_all()\n",
    "\n",
    "# 查看图结构中节点标签的类别，返回结果是一个frozenset\n",
    "print('\\nGraph node_labels:\\n', graph.schema.node_labels)\n",
    "\n",
    "# 查看图结构中关系的类型\n",
    "print('\\nGraph relationship_types:\\n', graph.schema.relationship_types)  \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 节点信息\n",
    "def node_info(node_x):\n",
    "    node_str = list()\n",
    "    node_str.append('{:15s}:{}'.format('identity', node_x.identity))\n",
    "    node_str.append('{:15s}:{}'.format('labels', node_x.labels))    \n",
    "    node_str.append('{:15s}:{}'.format('nodes', node_x.nodes))\n",
    "    node_str.append('{:15s}:{}'.format('values', node_x.keys()))     \n",
    "    node_str.append('{:15s}:{}'.format('values', node_x.values()))  \n",
    "    node_str.append('{:15s}:{}'.format('types', node_x.types()))\n",
    "    # node_str.append('{:15s}:{}'.format('relationships', node_x.relationships))    \n",
    "    # node_str.append('{:15s}:{}'.format('graph', node_x.graph))\n",
    "    \n",
    "    return '\\n'.join(node_str)\n",
    "\n",
    "\n",
    "# 关系信息\n",
    "def relationships_info(relationship_x):\n",
    "    rela_str = list()\n",
    "    rela_str.append('{:15s}:{}'.format('values', relationship_x))\n",
    "    rela_str.append('{:15s}:{}'.format('identity', relationship_x.identity))\n",
    "    rela_str.append('{:15s}:{}'.format('types', relationship_x.types()))\n",
    "    rela_str.append('{:15s}:{}'.format('labels', relationship_x.labels))\n",
    "    rela_str.append('{:15s}:{}'.format('nodes', relationship_x.nodes))\n",
    "    rela_str.append('{:15s}:{}'.format('relationships', relationship_x.relationships))\n",
    "    rela_str.append('{:15s}:{}'.format('start_node', relationship_x.start_node))\n",
    "    rela_str.append('{:15s}:{}'.format('end_node', relationship_x.end_node))\n",
    "    # rela_str.append('{:15s}:{}'.format('graph', relationship_x.graph))\n",
    "\n",
    "    return '\\n'.join(rela_str)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 创建节点 Node"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "identity       :0\n",
      "labels         ::Person_贾家\n",
      "nodes          :(Node('Person_贾家', age=18, name='贾宝玉'),)\n",
      "values         :dict_keys(['name', 'age'])\n",
      "values         :dict_values(['贾宝玉', 18])\n",
      "types          :frozenset()\n",
      "节点信息： {'name': '贾宝玉', 'age': 18}\n"
     ]
    }
   ],
   "source": [
    "# 创建节点\n",
    "node_x = Node('Person_贾家', name='贾宝玉', age=18)\n",
    "graph.create(node_x)\n",
    "# graph.merge(node_x,\"Person_贾家\",\"name\")   # 检查该节点在数据库中是否可用。 如果它不存在，它创建新节点。 否则，它不创建新的。\n",
    "\n",
    "print(node_info(node_x))\n",
    "\n",
    "# 节点存储信息\n",
    "print('节点信息：', dict(node_x.items()))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# dir(a)\n",
    "# help(a)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# graph.merge(Node('yuleT2',name='张杰2'),\"Person\",\"name\")       # 根据name属性对person结点进行merge"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n"
     ]
    }
   ],
   "source": [
    "# 判断是否存在节点\n",
    "print(graph.exists(graph.nodes[0]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 创建关系  Relationship"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "node_a:  (:Person_贾家 {name: '\\u8d3e\\u653f'})\n",
      "node_b:  (:Person {name: '\\u738b\\u592b\\u4eba'})\n",
      "\n",
      "\n",
      "values         :(贾政)-[:妻 {count: 1}]->(王夫人)\n",
      "identity       :0\n",
      "types          :frozenset({'妻'})\n",
      "labels         :<bound method Subgraph.labels of 妻(Node('Person_贾家', name='贾政'), Node('Person', name='王夫人'), count=1)>\n",
      "nodes          :(Node('Person_贾家', name='贾政'), Node('Person', name='王夫人'))\n",
      "relationships  :(妻(Node('Person_贾家', name='贾政'), Node('Person', name='王夫人'), count=1),)\n",
      "start_node     :(_1:Person_贾家 {name: '\\u8d3e\\u653f'})\n",
      "end_node       :(_2:Person {name: '\\u738b\\u592b\\u4eba'})\n",
      "\n",
      "values         :(王夫人)-[:夫 {}]->(贾政)\n",
      "identity       :1\n",
      "types          :frozenset({'夫'})\n",
      "labels         :<bound method Subgraph.labels of 夫(Node('Person', name='王夫人'), Node('Person_贾家', name='贾政'))>\n",
      "nodes          :(Node('Person', name='王夫人'), Node('Person_贾家', name='贾政'))\n",
      "relationships  :(夫(Node('Person', name='王夫人'), Node('Person_贾家', name='贾政')),)\n",
      "start_node     :(_2:Person {name: '\\u738b\\u592b\\u4eba'})\n",
      "end_node       :(_1:Person_贾家 {name: '\\u8d3e\\u653f'})\n",
      "\n"
     ]
    }
   ],
   "source": [
    "node_a = Node('Person_贾家',name='贾政')   # 多次执行将重复创建节点及关系 \n",
    "node_b = Node('Person',name='王夫人')\n",
    "\n",
    "# node_a =  graph.nodes[1]    # 获取已有节点不会重复创建节点及关系 \n",
    "# node_b =  graph.nodes[2]\n",
    "\n",
    "print('node_a: ', node_a)\n",
    "print('node_b: ', node_b)\n",
    "print('\\n')\n",
    "\n",
    "r1 = Relationship(node_a,\"妻\",node_b)  # 表示建立的关系，关系类型为“认识”， a-> b\n",
    "r1['count'] = 1    # 表示关系属性count，其值为1\n",
    "\n",
    "r2 = Relationship(node_b,\"夫\",node_a) # 表示建立的关系，关系类型为“认识”， b-> a\n",
    "\n",
    "graph.create(r1|r2)\n",
    "\n",
    "print(relationships_info(r1), end='\\n\\n')\n",
    "print(relationships_info(r2), end='\\n\\n')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "values         :(贾政)-[:妻 {count: 2}]->(王夫人)\n"
     ]
    }
   ],
   "source": [
    "# 关系属性赋值、更新属性值\n",
    "\n",
    "r1['count'] +=1\n",
    "graph.push(r1)\n",
    "print('{:15s}:{}'.format('values', r1))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "### 删除并写入红楼梦数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "表格Title：  \"head\",\"tail\",\"relation\",\"label\"\n",
      "\n",
      "  379 ['秦可卿', '秦业', 'daughter', '女']\n",
      "Graph node_labels:\n",
      " frozenset({'Person', 'Person_贾'})\n",
      "\n",
      "Graph relationship_types:\n",
      " frozenset({'妾', '女', '妹', '妻', '兄', '夫', '子'})\n"
     ]
    }
   ],
   "source": [
    "import csv \n",
    "\n",
    "\n",
    "# 删除当前图所有节点\n",
    "graph.delete_all()\n",
    "\n",
    "# 写入数据库\n",
    "with open('./triples.csv', 'r', encoding='gbk') as f:\n",
    "    # Title\n",
    "    print('表格Title： ', f.readline())\n",
    "\n",
    "    for i, item in enumerate(csv.reader(f)):\n",
    "        print('\\r{:5d} {}'.format(i, item), end='')\n",
    "\n",
    "        if item[3] not in ['兄', '妹', '夫', '妻', '妾', '子', '女']:\n",
    "            continue\n",
    "\n",
    "        if item[0].startswith('贾') or item[1].startswith('贾'):\n",
    "            p_start = 'Person_贾' if item[1].startswith('贾') else 'Person'\n",
    "            p_end = 'Person_贾' if item[0].startswith('贾') else 'Person'\n",
    "\n",
    "            start_node = Node(p_start, name=item[1])\n",
    "            end_node = Node(p_end, name=item[0])\n",
    "            relation = Relationship(start_node, item[3], end_node)\n",
    "            graph.merge(start_node, p_start, \"name\")\n",
    "            graph.merge(end_node, p_end, \"name\")\n",
    "            graph.merge(relation, \"Person\", \"name\")\n",
    "\n",
    "            \n",
    "# 查看图结构中节点标签的类别，返回结果是一个frozenset\n",
    "print('\\nGraph node_labels:\\n', graph.schema.node_labels)\n",
    "\n",
    "# 查看图结构中关系的类型\n",
    "print('\\nGraph relationship_types:\\n', graph.schema.relationship_types)  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 查询"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "节点数量：70\n",
      "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69]\n",
      "identity       :69\n",
      "labels         ::Person\n",
      "nodes          :(Node('Person', name='尤氏'),)\n",
      "values         :dict_keys(['name'])\n",
      "values         :dict_values(['尤氏'])\n",
      "types          :frozenset()\n"
     ]
    }
   ],
   "source": [
    "# 根据节点 ID 获取节点\n",
    "print('节点数量：{}'.format(len(graph.nodes)))\n",
    "print(list(graph.nodes))\n",
    "node_x = graph.nodes[69]\n",
    "\n",
    "print(node_info(node_x))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Node('Person_贾', name='贾琏')]\n",
      "identity       :14\n",
      "labels         ::Person_贾\n",
      "nodes          :(Node('Person_贾', name='贾琏'),)\n",
      "values         :dict_keys(['name'])\n",
      "values         :dict_values(['贾琏'])\n",
      "types          :frozenset()\n",
      "\n",
      "\n",
      "identity       :1\n",
      "labels         ::Person_贾\n",
      "nodes          :(Node('Person_贾', name='贾敏'),)\n",
      "values         :dict_keys(['name'])\n",
      "values         :dict_values(['贾敏'])\n",
      "types          :frozenset()\n",
      "\n",
      "identity       :2\n",
      "labels         ::Person_贾\n",
      "nodes          :(Node('Person_贾', name='贾赦'),)\n",
      "values         :dict_keys(['name'])\n",
      "values         :dict_values(['贾赦'])\n",
      "types          :frozenset()\n",
      "\n",
      "identity       :3\n",
      "labels         ::Person_贾\n",
      "nodes          :(Node('Person_贾', name='贾源'),)\n",
      "values         :dict_keys(['name'])\n",
      "values         :dict_values(['贾源'])\n",
      "types          :frozenset()\n",
      "\n",
      "identity       :4\n",
      "labels         ::Person_贾\n",
      "nodes          :(Node('Person_贾', name='贾代善'),)\n",
      "values         :dict_keys(['name'])\n",
      "values         :dict_values(['贾代善'])\n",
      "types          :frozenset()\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 根据节点信息搜索节点\n",
    "print(list(graph.nodes.match('Person_贾',name='贾琏')))\n",
    "print(node_info(list(graph.nodes.match('Person_贾',name='贾琏'))[0]), end='\\n\\n\\n')\n",
    "\n",
    "\n",
    "for i, node_x in enumerate(graph.nodes.match('Person_贾')):\n",
    "    print(node_info(node_x), end='\\n\\n')\n",
    "    \n",
    "    if i > 2:\n",
    "        break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "关系数量：62\n",
      "[57, 46, 45, 44, 7, 6, 5, 4, 40, 2, 42, 41, 3, 1, 0, 56, 51, 50, 49, 48, 47, 43, 10, 9, 8, 55, 54, 53, 52, 13, 12, 11, 16, 15, 14, 17, 18, 19, 21, 20, 58, 22, 23, 25, 24, 27, 26, 29, 28, 30, 31, 32, 35, 34, 33, 61, 60, 38, 37, 36, 39, 59]\n",
      "True\n",
      "values         :(贾源)-[:子 {}]->(贾代善)\n",
      "identity       :2\n",
      "types          :frozenset({'子'})\n",
      "labels         :<bound method Subgraph.labels of 子(Node('Person_贾', name='贾源'), Node('Person_贾', name='贾代善'))>\n",
      "nodes          :(Node('Person_贾', name='贾源'), Node('Person_贾', name='贾代善'))\n",
      "relationships  :(子(Node('Person_贾', name='贾源'), Node('Person_贾', name='贾代善')),)\n",
      "start_node     :(_3:Person_贾 {name: '\\u8d3e\\u6e90'})\n",
      "end_node       :(_4:Person_贾 {name: '\\u8d3e\\u4ee3\\u5584'})\n"
     ]
    }
   ],
   "source": [
    "print('关系数量：{}'.format(len(graph.relationships)))\n",
    "print(list(graph.relationships))\n",
    "\n",
    "# 获取关系\n",
    "r_x = graph.relationships[2]\n",
    "\n",
    "# 判断是否存在关系\n",
    "print(graph.exists(r_x))\n",
    "\n",
    "# 关系相关信息\n",
    "print(relationships_info(r_x))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[妾(Node('Person_贾', name='贾代善'), Node('Person', name='老姨奶奶'))]"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 关系为 '妾' 起始节点为 graph.nodes[2] 的所有关系 \n",
    "list(graph.relationships.match(r_type='妾', nodes=[graph.nodes[4]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[子(Node('Person_贾', name='贾源'), Node('Person_贾', name='贾代善'))]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 结束节点为 graph.nodes[4] 的所有关系 \n",
    "list(graph.relationships.match(nodes=[None, graph.nodes[4]]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[妻(Node('Person_贾', name='贾赦'), Node('Person', name='邢夫人')),\n",
       " 妻(Node('Person_贾', name='贾代善'), Node('Person_贾', name='贾母')),\n",
       " 妻(Node('Person_贾', name='贾政'), Node('Person', name='王夫人')),\n",
       " 妻(Node('Person_贾', name='贾珠'), Node('Person', name='李纨')),\n",
       " 妻(Node('Person_贾', name='贾琏'), Node('Person', name='王熙凤')),\n",
       " 妻(Node('Person_贾', name='贾宝玉'), Node('Person', name='薛宝衩')),\n",
       " 妻(Node('Person_贾', name='贾瑞之父'), Node('Person_贾', name='贾瑞之母')),\n",
       " 妻(Node('Person_贾', name='贾璜'), Node('Person', name='金氏')),\n",
       " 妻(Node('Person_贾', name='贾化'), Node('Person', name='娇杏')),\n",
       " 妻(Node('Person_贾', name='贾珍'), Node('Person', name='尤氏')),\n",
       " 妻(Node('Person_贾', name='贾蓉'), Node('Person', name='秦可卿'))]"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 关系为 '妻' 的所有关系连接\n",
    "list(graph.relationships.match(r_type='妻'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "## 删除"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "节点数量：70\n",
      "节点数量：69\n"
     ]
    }
   ],
   "source": [
    "# 删除节点\n",
    "print('节点数量：{}'.format(len(graph.nodes)))\n",
    "graph.delete(graph.nodes[0])  # 删除节点\n",
    "print('节点数量：{}'.format(len(graph.nodes)))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 删除当前图所有节点\n",
    "# graph.delete_all()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "# Cypher  \n",
    "[neo4j Cypher](https://www.jianshu.com/p/8b9b49e9e3cf)\n",
    "\n",
    "### 节点语法 \n",
    "Cypher采用一对()来表示节点.  \n",
    "():匿名节点,匹配所有的节点,如果想要操作匹配到的节点,需要加变量(matrix)  \n",
    "(matrix):赋有变量的节点,matrix将包含匹配到的所有节点,通过matrix变量可以对它们进行操作   \n",
    "(matrix:Movie): 指定了标签的节点,只会匹配标签为Moive的节点   \n",
    "(matrix:Movie {title:\"Haha\"}):指定了标签和属性的节点,只有节点标签是Movie,标题为Haha的节点会被匹配  \n",
    "\n",
    "\n",
    "### 关系语法  \n",
    "-- :表示无方向关系   \n",
    "-->:有方向关系   \n",
    "-[rale]->:给关系赋予一个变量,方便对其操作   \n",
    "-[rale:friend]->:匹配关系类型为friend类型的关系,并赋予rale变量接收   \n",
    "-[rale:friend {long_time:2}]->:给关系加条件,匹配friend类型的关系且属性long_time为2   \n",
    "  \n",
    "同时如果想要关系语法不想重复写,想要多个语句写的时候减少重复写,可以将关系语法赋予一个变量  \n",
    "acted_in = (people:Person)-[:acted_in]->(movie:Movie)  \n",
    "这样acted_in 就可以写到多个查询语句中,减少重复编写  \n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'a.name': '贾宝玉', 'a.age': None}]"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.run(\"match (a{name:'贾宝玉'}) return a.name,a.age\").data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<table><tr><th>a.name</th><th>a.age</th></tr><tr><td style=\"text-align:left\">贾宝玉</td><td style=\"text-align:right\">null</td></tr></table>"
      ],
      "text/plain": [
       " a.name | a.age \n",
       "--------|-------\n",
       " 贾宝玉    |  null "
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# graph.run(\"match (a{name:'贾宝玉'}) return a.name,a.age\").to_ndarray()  \n",
    "# graph.run(\"match (a{name:'贾宝玉'}) return a.name,a.age\").to_data_frame() \n",
    "graph.run(\"match (a{name:'贾宝玉'}) return a.name,a.age\").to_table()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "values         :(贾探春)-[:夫 {}]->(周琼之子)\n",
      "identity       :18\n",
      "types          :frozenset({'夫'})\n",
      "labels         :<bound method Subgraph.labels of 夫(Node('Person_贾', name='贾探春'), Node('Person', name='周琼之子'))>\n",
      "nodes          :(Node('Person_贾', name='贾探春'), Node('Person', name='周琼之子'))\n",
      "relationships  :(夫(Node('Person_贾', name='贾探春'), Node('Person', name='周琼之子')),)\n",
      "start_node     :(_24:Person_贾 {name: '\\u8d3e\\u63a2\\u6625'})\n",
      "end_node       :(_25:Person {name: '\\u5468\\u743c\\u4e4b\\u5b50'})\n",
      "\n",
      "\n",
      "values         :(贾迎春)-[:夫 {}]->(孙绍祖)\n",
      "identity       :56\n",
      "types          :frozenset({'夫'})\n",
      "labels         :<bound method Subgraph.labels of 夫(Node('Person_贾', name='贾迎春'), Node('Person', name='孙绍祖'))>\n",
      "nodes          :(Node('Person_贾', name='贾迎春'), Node('Person', name='孙绍祖'))\n",
      "relationships  :(夫(Node('Person_贾', name='贾迎春'), Node('Person', name='孙绍祖')),)\n",
      "start_node     :(_9:Person_贾 {name: '\\u8d3e\\u8fce\\u6625'})\n",
      "end_node       :(_66:Person {name: '\\u5b59\\u7ecd\\u7956'})\n",
      "\n",
      "\n",
      "values         :(贾敏)-[:夫 {}]->(林如海)\n",
      "identity       :57\n",
      "types          :frozenset({'夫'})\n",
      "labels         :<bound method Subgraph.labels of 夫(Node('Person_贾', name='贾敏'), Node('Person', name='林如海'))>\n",
      "nodes          :(Node('Person_贾', name='贾敏'), Node('Person', name='林如海'))\n",
      "relationships  :(夫(Node('Person_贾', name='贾敏'), Node('Person', name='林如海')),)\n",
      "start_node     :(_1:Person_贾 {name: '\\u8d3e\\u654f'})\n",
      "end_node       :(_67:Person {name: '\\u6797\\u5982\\u6d77'})\n"
     ]
    }
   ],
   "source": [
    "a = graph.run(\"MATCH p=()-[:`夫`]->(n:Person) RETURN p\").data()\n",
    "\n",
    "for a_i in a:\n",
    "    print('\\n')\n",
    "    a_i['p'].start_node\n",
    "    a_i['p'].end_node\n",
    "    print(relationships_info(a_i['p'].relationships[0]))\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'p': Path(Node('Person', name='娄氏'), 子(Node('Person', name='娄氏'), Node('Person_贾', name='贾菌')))},\n",
       " {'p': Path(Node('Person', name='五嫂子卜氏'), 子(Node('Person', name='五嫂子卜氏'), Node('Person_贾', name='贾芸')))},\n",
       " {'p': Path(Node('Person', name='周氏'), 子(Node('Person', name='周氏'), Node('Person_贾', name='贾芹')))},\n",
       " {'p': Path(Node('Person', name='史侯'), 女(Node('Person', name='史侯'), Node('Person_贾', name='贾母')))}]"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 关系为  非贾家人物 -> 贾家人物\n",
    "graph.run(\"MATCH p=(:Person)-->(:Person_贾) RETURN p \").data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'p': Path(Node('Person_贾', name='贾宝玉'), 子(Node('Person_贾', name='贾宝玉'), Node('Person_贾', name='贾桂')))},\n",
       " {'p': Path(Node('Person_贾', name='贾宝玉'), 妾(Node('Person_贾', name='贾宝玉'), Node('Person', name='花袭人')))},\n",
       " {'p': Path(Node('Person_贾', name='贾宝玉'), 妻(Node('Person_贾', name='贾宝玉'), Node('Person', name='薛宝衩')))}]"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 贾宝玉 为起点的所有关系 \n",
    "graph.run(\"MATCH p=({name:'贾宝玉'}) -->() RETURN p \").data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'p': Path(Node('Person_贾', name='贾宝玉'), 子(Node('Person_贾', name='贾政'), Node('Person_贾', name='贾宝玉')))},\n",
       " {'p': Path(Node('Person_贾', name='贾宝玉'), 子(Node('Person_贾', name='贾宝玉'), Node('Person_贾', name='贾桂')))},\n",
       " {'p': Path(Node('Person_贾', name='贾宝玉'), 妾(Node('Person_贾', name='贾宝玉'), Node('Person', name='花袭人')))},\n",
       " {'p': Path(Node('Person_贾', name='贾宝玉'), 妻(Node('Person_贾', name='贾宝玉'), Node('Person', name='薛宝衩')))}]"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 贾宝玉 为起点或终点的所有关系 \n",
    "graph.run(\"MATCH p=({name:'贾宝玉'}) -- () RETURN p \").data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'p_1.name': '贾代善', 'p_3.name': '贾环'},\n",
       " {'p_1.name': '贾代善', 'p_3.name': '贾宝玉'},\n",
       " {'p_1.name': '贾代善', 'p_3.name': '贾珠'},\n",
       " {'p_1.name': '贾代善', 'p_3.name': '贾琮'},\n",
       " {'p_1.name': '贾代善', 'p_3.name': '贾琏'}]"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 贾代善 的孙子\n",
    "cql = \"\"\"\n",
    "MATCH (p_1 {name:\"贾代善\"}) -[:子] ->()-[:子]->(p_3)\n",
    "RETURN p_1.name,p_3.name\n",
    "\"\"\"\n",
    "graph.run(cql).data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'p_1.name': '贾代善'}]"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 贾宝玉 的爷爷\n",
    "cql = \"\"\"\n",
    "MATCH (p_1) -[:子] ->()-[:子]->({name:\"贾宝玉\"})\n",
    "RETURN p_1.name\n",
    "\"\"\"\n",
    "graph.run(cql).data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'p': Node('Person_贾', name='贾迎春')},\n",
       " {'p': Node('Person_贾', name='贾探春')},\n",
       " {'p': Node('Person_贾', name='贾惜春')},\n",
       " {'p': Node('Person_贾', name='贾元春')}]"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 名字结尾为春的人名\n",
    "cql = \"\"\"\n",
    "MATCH (p)\n",
    "WHERE p.name =~ '.*?春'\n",
    "RETURN  p\n",
    "\"\"\"\n",
    "graph.run(cql).data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'p1': Node('Person_贾', name='贾迎春')},\n",
       " {'p1': Node('Person_贾', name='贾探春')},\n",
       " {'p1': Node('Person_贾', name='贾惜春')},\n",
       " {'p1': Node('Person_贾', name='贾元春')}]"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 名字结尾为春的人名\n",
    "cql = \"\"\"\n",
    "MATCH (p1:Person_贾)\n",
    "WHERE  p1.name ENDS WITH '春'\n",
    "RETURN  p1\n",
    "\"\"\"\n",
    "graph.run(cql).data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'p1': Node('Person_贾', name='贾代善')},\n",
       " {'p1': Node('Person_贾', name='贾迎春')},\n",
       " {'p1': Node('Person_贾', name='贾宝玉')},\n",
       " {'p1': Node('Person_贾', name='贾探春')},\n",
       " {'p1': Node('Person_贾', name='贾代化')},\n",
       " {'p1': Node('Person_贾', name='贾惜春')},\n",
       " {'p1': Node('Person_贾', name='贾代儒')},\n",
       " {'p1': Node('Person_贾', name='贾四姐')},\n",
       " {'p1': Node('Person_贾', name='贾王扁')},\n",
       " {'p1': Node('Person_贾', name='贾喜鸾')},\n",
       " {'p1': Node('Person_贾', name='贾元春')},\n",
       " {'p1': Node('Person_贾', name='贾巧姐')}]"
      ]
     },
     "execution_count": 30,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 节点类别为 'Person_贾', 名字长度为 3 的节点 \n",
    "cql = \"\"\"\n",
    "MATCH (p1:Person_贾)\n",
    "WHERE (p1.name) =~ '...' \n",
    "RETURN  p1\n",
    "\"\"\"\n",
    "graph.run(cql).data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{'p1': Node('Person_贾', name='贾代善')},\n",
       " {'p1': Node('Person_贾', name='贾代化')},\n",
       " {'p1': Node('Person_贾', name='贾代儒')}]"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 节点名字中包含 代 的节点\n",
    "cql = \"\"\"\n",
    "MATCH (p1)\n",
    "WHERE (p1.name) CONTAINS '代'\n",
    "RETURN  p1\n",
    "\"\"\"\n",
    "graph.run(cql).data()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "/d/Desktop/Neo4j\n"
     ]
    }
   ],
   "source": [
    "! pwd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "python(py37)",
   "language": "python",
   "name": "py36"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
